package com.atty.dms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.atty.dms.common.biz.user.UserContext;
import com.atty.dms.common.convention.exception.ClientException;
import com.atty.dms.common.enums.UserRoleCodeEnum;
import com.atty.dms.dao.entity.DormitoryDO;
import com.atty.dms.dao.mapper.DormitoryMapper;
import com.atty.dms.dto.req.DormitoryCreateReqDTO;
import com.atty.dms.dto.req.DormitoryUpdateReqDTO;
import com.atty.dms.dto.resp.DormitoryRespDTO;
import com.atty.dms.dto.resp.UserRespDTO;
import com.atty.dms.service.DormitoryService;
import com.atty.dms.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * ClassName:DormitoryServiceImpl
 * Package:com.atty.dms.service.impl
 * Description:
 *
 * @Author:tony
 * @Create :2025/4/15 9:35
 * @Version :1.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class DormitoryServiceImpl extends ServiceImpl<DormitoryMapper, DormitoryDO> implements DormitoryService {

    private final UserService userService;

    @Override
    public DormitoryRespDTO getDormitoryById(String dormitoryId) {
        return getDormitoryByField(DormitoryDO::getDormitoryId, dormitoryId, "宿舍ID不能为空");
    }

    @Override
    public DormitoryRespDTO getDormitoryByDormitoryNumber(String dormitoryNumber) {
        return getDormitoryByField(DormitoryDO::getDormitoryNumber, dormitoryNumber, "宿舍编号不能为空");
    }

    /**
     * 通用方法：根据字段查询宿舍信息
     *
     * @param fieldFunction 字段的函数引用（如 DormitoryDO::getDormitoryId）
     * @param fieldValue     字段值（如 dormitoryId 或 dormitoryNumber）
     * @param errorMessage   参数为空时的错误提示信息
     * @return 宿舍响应 DTO
     */
    private DormitoryRespDTO getDormitoryByField(SFunction<DormitoryDO, ?> fieldFunction, Object fieldValue, String errorMessage) {
        // 参数校验
        if (fieldValue == null || (fieldValue instanceof String && StringUtils.isBlank((String) fieldValue))) {
            throw new IllegalArgumentException(errorMessage);
        }
        // 构建查询条件
        LambdaQueryWrapper<DormitoryDO> queryWrapper = Wrappers.lambdaQuery(DormitoryDO.class)
                .eq(fieldFunction, fieldValue);
        // 查询宿舍信息
        DormitoryDO dormitoryDO = baseMapper.selectOne(queryWrapper);
        if (dormitoryDO == null) {
            throw new ClientException("宿舍不存在");
        }

        // 转换为响应对象
        DormitoryRespDTO dormitoryRespDTO = new DormitoryRespDTO();
        BeanUtils.copyProperties(dormitoryDO, dormitoryRespDTO);
        return dormitoryRespDTO;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createDormitory(DormitoryCreateReqDTO requestParam) {
        if(StringUtils.isBlank(requestParam.getDormitoryNumber())){
            throw new ClientException("宿舍编号不能为空");
        }
        //查询当前用户是否有权限
        checkUserRoleByUserContext();
            try {
                DormitoryDO dormitoryDO = BeanUtil.toBean(requestParam, DormitoryDO.class);
                log.info("尝试插入宿舍信息: {}", dormitoryDO);
                int insert = baseMapper.insert(dormitoryDO);
                if (insert < 1) {
                    log.error("插入宿舍信息失败: {}", dormitoryDO);
                    throw new ClientException("创建宿舍失败");
                }
            } catch (Exception e) {
                log.error("创建宿舍时发生异常，宿舍信息：{}", requestParam, e);
                if (e.getMessage().contains("Duplicate entry")) { // MySQL 唯一约束冲突
                    throw new ClientException("宿舍编号已存在，无法创建");
                } else {
                    throw new ClientException("创建宿舍失败，请稍后重试");
                }
            }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateDormitory(DormitoryUpdateReqDTO requestParam) {
        if(StringUtils.isBlank(requestParam.getDormitoryId())){
            throw new ClientException("宿舍ID不能为空");
        }
        checkUserRoleByUserContext();
            try {
                DormitoryDO dormitoryDO = BeanUtil.toBean(requestParam, DormitoryDO.class);
                LambdaUpdateWrapper<DormitoryDO> updateWrapper = Wrappers.lambdaUpdate(DormitoryDO.class)
                        .eq(DormitoryDO::getDormitoryId, requestParam.getDormitoryId());
                int update = baseMapper.update(dormitoryDO, updateWrapper);
                if (update < 1){
                    log.warn("更新宿舍信息失败，dormitoryId: {}", requestParam.getDormitoryId());
                    throw new ClientException("更新宿舍信息失败，请检查宿舍ID是否正确");
                }
            }catch(Exception ex){
                log.error("数据库访问异常，详情：{}, 请求参数: {}", ex.getMessage(), requestParam, ex);
                throw new ClientException("已经有同名宿舍号码 或 数据库访问异常");
            }


    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteDormitoryById(String dormitoryId) {
        if(StringUtils.isBlank(dormitoryId)){
            throw new ClientException("宿舍ID不能为空");
        }
        //查询当前用户是否有权限
        checkUserRoleByUserContext();
        // 删除宿舍信息
        LambdaQueryWrapper<DormitoryDO> queryWrapper = Wrappers.lambdaQuery(DormitoryDO.class)
                .eq(DormitoryDO::getDormitoryId, dormitoryId);
        int delete = baseMapper.delete(queryWrapper);

        if (delete < 1) {
            log.error("删除宿舍失败，dormitoryId: {}", dormitoryId);
            throw new ClientException("宿舍不存在，请检查宿舍ID是否正确");
        }
    }

    @Override
    public Page<DormitoryRespDTO> getAllDormitoriesByPage(int pageNum, int sizeNum) {
        log.info("开始分页查询宿舍信息，pageNum: {}, sizeNum: {}", pageNum, sizeNum);
        // 1. 创建分页对象
        Page<DormitoryDO> dormitoryPage = new Page<>(pageNum, sizeNum);
        // 2. 执行分页查询
        LambdaQueryWrapper<DormitoryDO> queryWrapper = Wrappers.lambdaQuery(DormitoryDO.class)
                .orderByAsc(DormitoryDO::getDormitoryId); // 按宿舍 ID 升序排序
        Page<DormitoryDO> resultPage = baseMapper.selectPage(dormitoryPage, queryWrapper);
        // 3. 检查是否有数据
        if (resultPage.getRecords().isEmpty()) {
            log.warn("分页查询宿舍信息失败，未找到任何宿舍信息");
            throw new ClientException("当前没有宿舍信息");
        }
        // 4. 将 DormitoryDO 转换为 DormitoryRespDTO
        List<DormitoryRespDTO> dormitoryRespDTOList = resultPage.getRecords().stream()
                .map(dormitoryDO -> {
                    DormitoryRespDTO dto = new DormitoryRespDTO();
                    BeanUtils.copyProperties(dormitoryDO, dto); // 使用 BeanUtils 进行属性拷贝
                    return dto;
                })
                .toList();
        log.info("成功将 {} 条宿舍信息转换为响应对象", dormitoryRespDTOList.size());
        // 5. 构造返回的分页对象
        Page<DormitoryRespDTO> respPage = new Page<>();
        BeanUtils.copyProperties(resultPage, respPage, "records"); // 复制分页信息
        respPage.setRecords(dormitoryRespDTOList); // 设置转换后的记录
        log.info("分页查询宿舍信息完成，总记录数: {}, 当前页记录数: {}", resultPage.getTotal(), dormitoryRespDTOList.size());
        return respPage;
    }


    private void checkUserRoleByUserContext(){
        String username = UserContext.getUsername();
        if (StringUtils.isBlank(username)) {
            log.error("用户上下文中未获取到用户名");
            throw new ClientException("用户上下文中，当前用户信息不存在");
        }
        UserRespDTO userRespDTO = userService.getUserByUsername(username);
        if(userRespDTO == null || userRespDTO.getRole() == null){
            log.error("用户上下文中，当前用户不存在");
            throw new ClientException("用户上下文中，当前用户不存在");
        }
        if(!userRespDTO.getRole().equals(UserRoleCodeEnum.USER_ROLE_ADMIN.code()) ){
            log.info("用户 {} 尝试执行需要管理员权限的操作", username);
            throw new ClientException("您没有权限进行此操作");
        }
    }


}



